<template>
  <!-- Tree 树组件，支持远程或静态数据 -->
  <a-tree v-bind="$attrs" :treeData="finalOptions" :loading="loading" />
</template>

<script setup lang="ts">
import { ref, watch, onMounted, computed } from 'vue'

// 定义组件 Props 接口
interface Props {
  api?: (_params?: any) => Promise<any> // 可选的远程加载函数
  params?: Record<string, any> // 请求 API 的参数
  options?: any[] // 静态树数据（优先级高于 api）
  resultField?: string // 接口返回的字段路径
  labelField?: string // 显示 label 的字段名
  valueField?: string // 用作 key 的字段名
  childrenField?: string // 子节点字段名
  immediate?: boolean // 是否挂载时立即加载数据
}

// 设置默认值
const props = withDefaults(defineProps<Props>(), {
  options: () => [], // 默认静态 options 为空数组
  labelField: 'title', // 默认 label 使用 title 字段
  valueField: 'key', // 默认 key 使用 key 字段
  childrenField: 'children', // 默认子节点字段名为 children
  immediate: true // 默认挂载立即加载数据
})

const loading = ref(false) // 加载状态
const dynamicOptions = ref<any[]>([]) // 远程加载的数据源

// 最终用于渲染的数据，优先使用 props.options，否则使用动态数据
const finalOptions = computed(() => {
  return props.options?.length ? props.options : dynamicOptions.value
})

// 获取远程数据
const fetchData = async () => {
  if (!props.api || props.options?.length) return // 若有静态 options 则跳过加载
  loading.value = true
  try {
    const res = await props.api(props.params) // 调用 API 获取数据
    const list = props.resultField ? res[props.resultField] || [] : res

    // 递归转换树结构的字段名
    const transformTree = (data: any[]): any[] =>
      data.map((item: any) => ({
        title: item[props.labelField], // 显示的标题字段
        key: item[props.valueField], // 用作树节点的 key
        children: Array.isArray(item[props.childrenField]) // 递归处理子节点
          ? transformTree(item[props.childrenField])
          : undefined
      }))

    // 设置动态 options
    dynamicOptions.value = Array.isArray(list) ? transformTree(list) : []
  } catch (err) {
    console.error('ApiTree fetch error:', err) // 捕获请求错误
  } finally {
    loading.value = false // 无论如何结束 loading
  }
}

// 监听参数变化自动重新拉取数据
watch(() => props.params, fetchData, { deep: true })

// 初始化加载数据
onMounted(() => {
  if (props.immediate && !props.options?.length) {
    fetchData()
  }
})
</script>
